﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Communication.Lib.Core;
using Communication.Lib.Mode;
using log4net;

namespace Communication.Lib.Protocol
{
    public class DemoProtocol : IProtocolable<DemoInfo>
    {
        private static ILog _logger = LogManager.GetLogger(typeof(DemoProtocol));

        private static object _lockobj = new object();
        private static DemoProtocol _instance = null;

        private const byte FirstByte = 0xaa;
        private const byte SecondByte = 0x55;

        public static DemoProtocol Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (_lockobj)
                    {
                        _instance = new DemoProtocol();
                    }
                }
                return _instance;
            }
        }

        private static List<byte> _bytebuffer;
        private const int Length = 7;

        private DemoProtocol()
        {
            _bytebuffer = new List<byte>();
        }

        private bool DecodeData(byte[] bytes, out float data, out byte flag)
        {
            int index = bytes.Length - 1;
            data = 0;
            flag = 0;
            if (bytes[index] != GetCheckData(bytes.Take(index).ToArray()))
            {
                _logger.Error("CheckData Error.校验位异常");
                return false;
            }
            flag = (bytes[2]);
            data = BitConverter.ToUInt16(bytes, 3) * 0.1f;
            return true;
        }

        private byte GetCheckData(byte[] toArray)
        {
            byte res = 0;
            for (int i = 0; i < toArray.Length; i++)
            {
                res += toArray[i];
            }

            return res;
        }

        public byte[] EncodeBytes(DemoInfo info)
        {
            List<byte> list = new List<byte>();
            list.Add(FirstByte);
            list.Add(SecondByte);
            list.Add(Convert.ToByte(info.Valid));
            list.AddRange(BitConverter.GetBytes(Convert.ToUInt16(info.Data * 10.0)));
            list.Add(0x00);
            list.Add(GetCheckData(list.ToArray()));
            return list.ToArray();
        }

        private DemoInfo DecodeData(byte[] bytes)
        {
            DemoInfo info = new DemoInfo();
            try
            {
                if (!DecodeData(bytes, out var height, out var valid)) return null;
                info.Data = height;
                info.Valid = valid;
            }
            catch (Exception ex)
            {
                _logger.Error($"DecodeData Error. {ex}");
            }
            return info;
        }

        public void AddBytes(byte[] bytes)
        {
            if (_bytebuffer.Count > 700) _bytebuffer.Clear();
            _bytebuffer.AddRange(bytes);
            new Task(() =>
            {
                var s = bytes.FormatAsHex();
                _logger.Debug($"altimeter decode databytes: {s} ");
            }).Start();
        }

        public DemoInfo DecodeData()
        {
            byte[] toDeBytes = GetBytesFromBuffer();
            if (toDeBytes == null || toDeBytes.Length < Length)
            {
                return null;
            }
            return DecodeData(toDeBytes);
        }

        #region 数据缓存

        private byte[] GetBytesFromBuffer()
        {
            byte[] res = null;
            if (_bytebuffer.Count >= Length)
            {
                int index = _bytebuffer.IndexOf(FirstByte, 0);
                if (index > -1 && index <= _bytebuffer.Count - Length)//有帧头 可截取
                {
                    if (_bytebuffer[index + 1] == SecondByte) //帧头2字节正常
                    {
                        res = _bytebuffer.Skip(index).Take(Length).ToArray();
                        _bytebuffer.RemoveRange(0, index + Length);
                    }
                    else //帧头2字节异常  舍弃帧头第一字节
                    {
                        _bytebuffer.RemoveRange(0, index + 1);
                    }
                }
                //没有帧头 返回空
            }
            //不足一帧 返回空
            return res;
        }

        #endregion 数据缓存
    }
}